import random
import time
import cv2
import json
import numpy as np
import pyautogui
import mss
from dataclasses import dataclass, asdict
from typing import Tuple, Optional
import keyboard
pyautogui.PAUSE = 0

file_path = "a.json"


@dataclass
class Config:
    red_point: Optional[Tuple[int, int]] = None  # 屏幕坐标(x,y)
    # red_dot_color: Tuple[int, int, int] = (255, 0, 0)
    # white_threshold: float = 0.7
    # check_positions: Optional[List[Tuple[int, int]]] = None

    @classmethod
    def load(cls, filepath: str) -> 'Config':
        """从JSON文件加载配置,文件不存在时返回默认配置"""
        try:
            with open(filepath, 'r') as f:
                data = json.load(f)
                # 转换JSON数组为Python元组
                if 'red_dot_color' in data:
                    data['red_dot_color'] = tuple(data['red_dot_color'])
                if 'check_positions' in data:
                    data['check_positions'] = [
                        tuple(pos) for pos in data['check_positions']]
                return cls(**data)
        except FileNotFoundError:
            return cls()  # 返回默认配置
        except json.JSONDecodeError:
            print(f"Warning: Invalid JSON format in {filepath}")
            return cls()

    def save(self, filepath: str) -> None:
        """保存配置到JSON文件"""
        data = asdict(self)
        with open(filepath, 'w') as f:
            json.dump(data, f, indent=4)


class FishingPlugin:
    def __init__(self):
        self.is_running = False
        self.is_pause = True
        # self.cfg = Config()
        self.cfg = Config.load(file_path)
        self.srcdc = mss.mss()
        self.last_action_time = 0
        self.random_delay = lambda: random.uniform(0.1, 0.5)
        self._register_hotkeys()
        pass

    # def human_like_click(self, x, y):
    #     """带同步检测的人类点击模拟"""
    #     # 先截图（点击前状态）
    #     with mss.mss() as sct:
    #         monitor = {
    #             "top": max(0, y - 500),
    #             "left": max(0, x - 500),
    #             "width": 1000,
    #             "height": 1000
    #         }
    #         pre_click = sct.grab(monitor)

    #         # 执行点击
    #         pyautogui.mouseDown(button='left')
    #         time.sleep(0.5)  # 适当延长确保游戏响应
    #         pyautogui.mouseUp(button='left')

    #         # 点击后截图（需等待渲染）
    #         time.sleep(0.2)  # 关键：等待游戏界面更新
    #         # pyautogui.mouseInfo()
    #         post_click = sct.grab(monitor)

    #         # 可视化对比
    #         cv2.imshow("Pre-Click", np.array(pre_click)[:, :, :3])
    #         cv2.imshow("Post-Click", np.array(post_click)[:, :, :3])
    #         cv2.waitKey(0)

    def human_like_click(self, x, y):
        """模拟人类点击行为"""
        pyautogui.moveTo(
            x + random.randint(-5, 5),
            y + random.randint(-5, 5),
            duration=random.uniform(0.5, 1)
        )
        # pyautogui.mouseUp(button='left')
        time.sleep(0.5)  # 短暂保持按压状态
        pyautogui.mouseDown(button='left')
        time.sleep(0.2)  # 短暂保持按压状态
        pyautogui.mouseUp(button='left')

    def _register_hotkeys(self):
        keyboard.add_hotkey('esc', self._stop_running)
        keyboard.add_hotkey('f4', self._red_point_up)

    def _stop_running(self):
        self.is_running = False

    def detect_red_point(self, center_point, search_size, screenshot_name=None):
        with mss.mss() as sct:
            """
            修正版红点检测函数
            :param center_point: (x,y) 中心坐标
            :param search_size: 正方形边长
            :param screenshot_name: 截图保存路径
            :return: 红点坐标或None
            """
            x, y = center_point
            half_size = search_size // 2
            monitor = {
                "top": max(0, y - half_size),
                "left": max(0, x - half_size),
                "width": search_size,
                "height": search_size
            }
            screen = sct.grab(monitor)
            screen = np.array(screen)[:, :, :3]
            screen = cv2.cvtColor(screen, cv2.COLOR_BGRA2BGR)
            red_mask = cv2.inRange(screen, np.array(
                [0, 0, 200]), np.array([100, 100, 255]))

            # cv2.imshow("Original", screen)
            # cv2.imshow("Red Mask", red_mask)
            # cv2.waitKey(0)

            if np.any(red_mask):
                contours, _ = cv2.findContours(
                    red_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
                if contours:
                    M = cv2.moments(max(contours, key=cv2.contourArea))
                    if M["m00"] > 0:
                        red_x = x - half_size + int(M["m10"]/M["m00"])
                        red_y = y - half_size + int(M["m01"]/M["m00"])
                        if screenshot_name:
                            # print(type(screen))
                            # img = np.zeros((200, 200, 3), dtype=np.uint8)
                            # print(type(img))

                            cv2.circle(
                                screen, (int(M["m10"]/M["m00"]), int(M["m01"]/M["m00"])), 5, (0, 255, 0), 2)

                            cv2.imwrite(screenshot_name+".png", screen)
                        return (red_x, red_y)
            if screenshot_name:
                cv2.imwrite(f"{screenshot_name}_err.png", screen)
            return None

    def _red_point_up(self):
        """更新红点坐标（使用1000x1000区域）"""
        center = (pyautogui.size().width//2, pyautogui.size().height//2)
        if red_point := self.detect_red_point(center, 1000, "red_point_debug"):
            self.cfg.red_point = red_point
            print(f"坐标更新: {red_point}")
            return True
        self.cfg.red_point = None
        print("红点检测失败")
        return False

    def idle2fish(self):
        """钓鱼主逻辑"""
        max_white = 0
        i = 0
        if not self.cfg.red_point:
            print("未设置红点坐标")
            return False
        x, y = self.cfg.red_point
        # self.human_like_click(x, y)
        # time.sleep(2 + random.uniform(-0.5, 0.5))

        while not (new_point := self.detect_red_point((x, y), 400, "idle2fish")) and self.is_running:
            if i < 10:
                i = i+1
                time.sleep(0.5)
                continue

            self.cfg.red_point = None
            print("红点消失")
            return False
        self.is_idle = True

        self.cfg.red_point = new_point
        x, y = self.cfg.red_point
        monitor = {
            "top": new_point[1]-200, "left": new_point[0]-200, "width": 400, "height": 400}

        start_time = time.time()
        with mss.mss() as sct:
            while self.is_running and (time.time() - start_time < 20):
                screen = np.array(sct.grab(monitor))[100:300, 100:300]
                white_surge = np.mean(cv2.cvtColor(
                    screen, cv2.COLOR_BGR2GRAY) > 200)
                if white_surge > max_white:
                    max_white = white_surge
                    # print(white_surge)
                if white_surge > 0.03:
                    # pyautogui.mouseDown(button='left')
                    return True
                time.sleep(0.2)
        print("钓鱼超时")
        return False

    def check_color(self, pos):
        """检查指定位置的颜色"""
        x, y = pos
        pixel = pyautogui.pixel(x, y)
        return np.array(pixel)

    def fishing(self):
        """钓鱼主控制函数"""
        width = pyautogui.size().width
        height = pyautogui.size().height
        pyautogui.mouseDown(button='left')  # 按住左键开始钓鱼
        monitor = {
            "top": 0,
            "left": 0,
            "width": width,
            "height": height
        }
        a_pos = (width//2 - 45, height//2)  # 左侧检测点
        d_pos = (width//2 + 45, height//2)  # 左侧检测点
        catched_pos = (width//2 + 1080, height//2+880)  # 左侧检测点
        idle_pos = (width//2 + 450, height//2+950)  # 左侧检测点
        white_threshold = 200  # 白色RGB阈值
        blue_lower = np.array([80, 64, 128], dtype=np.uint8)  # 蓝色下限
        blue_upper = np.array([100, 200, 230], dtype=np.uint8)  # 蓝色上限
        # b_pos = (screen_width//2 + 45, screen_height//2)  # 右侧检测点
        with mss.mss() as sct:
            while self.is_running:
                time.sleep(0.1)  # 每0.1秒检测一次
                screen = sct.grab(monitor)
                screen = np.array(screen)[:, :, :3]
                screen = cv2.cvtColor(screen, cv2.COLOR_BGRA2BGR)
                # 检查位置a
                a_pixel = screen[a_pos[1], a_pos[0]]
                d_pixel = screen[d_pos[1], d_pos[0]]
                catched_pixel = screen[catched_pos[1], catched_pos[0]]
                idle_pixel = screen[idle_pos[1], idle_pos[0]]
                if np.all(a_pixel > white_threshold):
                    pyautogui.keyDown('a')
                    pyautogui.keyUp('d')

                if np.all(d_pixel > white_threshold):
                    pyautogui.keyDown('d')
                    pyautogui.keyUp('a')

                if np.all(catched_pixel > white_threshold):
                    pyautogui.keyUp('a')
                    pyautogui.keyUp('d')
                    pyautogui.mouseUp(button='left')
                    self.human_like_click(catched_pos[0], catched_pos[1])
                    time.sleep(1)
                    print("fish true")
                    return True

                hsv_pixel = cv2.cvtColor(
                    np.uint8([[idle_pixel]]), cv2.COLOR_BGR2HSV)[0][0]
                # print(hsv_pixel)
                if np.all((hsv_pixel >= blue_lower) & (hsv_pixel <= blue_upper)):
                    pyautogui.keyUp('a')
                    pyautogui.keyUp('d')
                    pyautogui.mouseUp(button='left')
                    time.sleep(1)
                    print("fish false")
                    return False
            print("退出fishing")
            pyautogui.keyUp('a')
            pyautogui.keyUp('d')
            pyautogui.mouseUp(button='left')

    def test_left_right(self):
        max_white_ratio = 0.003
        x, y = (pyautogui.size().width//2, pyautogui.size().height//2)
        search_size = 2000
        half_size = search_size // 2
        i = 0
        with mss.mss() as sct:
            monitor = {
                "top": max(0, y - half_size),
                "left": max(0, x - half_size),
                "width": search_size,
                "height": search_size
            }
            while self.is_running:

                screen = sct.grab(monitor)
                screen = np.array(screen)[:, :, :3]
                screen = cv2.cvtColor(screen, cv2.COLOR_BGRA2BGR)
                # 计算白色像素占比
                white_pixels = np.all(screen >= 200, axis=2)
                white_ratio = np.count_nonzero(
                    white_pixels) / white_pixels.size
                if (white_ratio > max_white_ratio):
                    print(white_ratio)
                    max_white_ratio = white_ratio

                    marked_img = cv2.circle(screen.copy(),
                                            (1000-45, 1000),
                                            5, (0, 0, 255), 1)
                    cv2.imwrite(f'a{i}.png', marked_img)
                    i = i+1
                    # time.sleep(10)

                time.sleep(0.2)

            print(f"白色像素占比: {white_ratio:.2%}")

        pass

    def test_catched(self):
        x, y = (pyautogui.size().width//2, pyautogui.size().height//2)
        with mss.mss() as sct:
            monitor = {
                "top": 0,
                "left": 0,
                "width": pyautogui.size().width,
                "height": pyautogui.size().height
            }
            screen = sct.grab(monitor)
            screen = np.array(screen)[:, :, :3]
            screen = cv2.cvtColor(screen, cv2.COLOR_BGRA2BGR)
            marked_img = cv2.circle(screen.copy(),
                                    (x+00, y+00),
                                    5, (0, 0, 255), 2)
            for i in range(10):
                marked_img = cv2.circle(marked_img,
                                        (x+1000+i*10, y+800+i*10),
                                        5, (0, 0, 255), 2)
            marked_img = cv2.circle(marked_img,
                                    (x+1080, y+880),
                                    5, (0, 0, 255), 2)
            cv2.imwrite(f'a.png', marked_img)  # 1080 880

    def test_idle(self):
        x, y = (pyautogui.size().width//2, pyautogui.size().height//2)
        with mss.mss() as sct:
            monitor = {
                "top": 0,
                "left": 0,
                "width": pyautogui.size().width,
                "height": pyautogui.size().height
            }
            screen = sct.grab(monitor)
            screen = np.array(screen)[:, :, :3]
            screen = cv2.cvtColor(screen, cv2.COLOR_BGRA2BGR)
            marked_img = cv2.circle(screen.copy(),
                                    (x+00, y+00),
                                    5, (0, 0, 255), 2)
            for i in range(10):
                marked_img = cv2.circle(marked_img,
                                        (x+400+i*10, y+900+i*10),
                                        5, (0, 0, 255), 2)
            marked_img = cv2.circle(marked_img,
                                    (x+450, y+950),
                                    2, (0, 0, 255), 1)
            cv2.imwrite(f'a.png', marked_img)  # 450 950
        pass

    def test_yugan(self):
        x, y = (pyautogui.size().width//2, pyautogui.size().height//2)
        with mss.mss() as sct:
            monitor = {
                "top": 0,
                "left": 0,
                "width": pyautogui.size().width,
                "height": pyautogui.size().height
            }
            screen = sct.grab(monitor)
            screen = np.array(screen)[:, :, :3]
            screen = cv2.cvtColor(screen, cv2.COLOR_BGRA2BGR)
            marked_img = cv2.circle(screen.copy(),
                                    (x+00, y+00),
                                    5, (0, 0, 255), 2)
            # for i in range(10):
            #     marked_img = cv2.circle(marked_img,
            #                             (x+1500+i*10, y+100+i*10),
            #                             5, (0, 0, 255), 2)
            marked_img = cv2.circle(marked_img,
                                    (x+1460, y+895),
                                    2, (0, 0, 255), 1)
            marked_img = cv2.circle(marked_img,
                                    (x+1412, y+950),
                                    2, (0, 0, 255), 1)
            marked_img = cv2.circle(marked_img,
                                    (x+1515, y+110),
                                    2, (0, 0, 255), 1)
            cv2.imwrite(f'a.png', marked_img)  # 450 950
        pass

    def idle(self):
        time.sleep(1)
        width = pyautogui.size().width
        height = pyautogui.size().height
        yugan_pos = width//2+1460, height//2+895
        monitor = {
            "top": 0,
            "left": 0,
            "width": pyautogui.size().width,
            "height": pyautogui.size().height
        }
        orange_lower = np.array([10, 100, 150], dtype=np.uint8)  # 橘红色下限
        orange_upper = np.array([25, 255, 255], dtype=np.uint8)  # 橘红色上限
        with mss.mss() as sct:
            screen = sct.grab(monitor)
            screen = np.array(screen)[:, :, :3]
            screen = cv2.cvtColor(screen, cv2.COLOR_BGRA2BGR)
            yugan_pixel = screen[yugan_pos[1], yugan_pos[0]]
            hsv_pixel = cv2.cvtColor(
                np.uint8([[yugan_pixel]]), cv2.COLOR_BGR2HSV)[0][0]
            if np.all((hsv_pixel >= orange_lower) & (hsv_pixel <= orange_upper)):
                pyautogui.keyDown('alt')
                time.sleep(0.1)
                self.human_like_click(width//2+1412, height//2+950)
                time.sleep(0.5)
                self.human_like_click(width//2+1515, height//2+110)
                time.sleep(0.1)
                pyautogui.keyUp('alt')
                time.sleep(0.5)
        #         return False
        # return True
        time.sleep(0.5)
        self.human_like_click(width//2, height//2)
        time.sleep(2)
        pass

    def run(self):
        self.is_running = True
        self.is_idle = False
        while self.is_running:

            while self.cfg.red_point is None:
                self.is_idle = False
                print("红点位置不存在,请更新红点位置.")
                time.sleep(2)
                continue

            if self.is_idle:
                self.idle()

            if self.is_running is False:
                break

            if self.idle2fish() is False:
                continue

            if self.is_running is False:
                break

            self.fishing()

            # self.test_left_right()

            # time.sleep()
        # self.cfg.save()


if __name__ == "__main__":
    bot = FishingPlugin()
    bot.run()
    # time.sleep(2)
    # print(bot.fishing())
    # print(bot.idle())
    # bot.test_catched()
    # bot.test_idle()
    # bot.test_yugan()
